#![allow(dead_code)]

struct ResultLrn {}

impl ResultLrn {
    pub fn hello() {
        println!("Result learning!");
    }
}

#[cfg(test)]
mod tests {
    // use super::*;
    use std::error;
    use std::io;

    #[test]
    #[allow(clippy::bool_assert_comparison)]
    /// NOTE: error::Error is Trait, io::Error is Struct
    /// is_ok(), is_ok_and(), is_err(), is_err_and()
    fn test_is_ok_or_err() {
        let result: Result<i32, Box<dyn error::Error>> = Ok(1); // NOTE: error::Error是trait. Box<dyn error::Error> 是实现了Error trait的类型
        assert!(result.is_ok());
        assert!(result.as_ref().is_ok_and(|&x| x == 1));
        assert_eq!(result.is_err(), false); // adding #[allow()]
        let result: Result<i32, io::Error> = Err(io::Error::new(io::ErrorKind::NotFound, "!")); // NOTE: io::Error is struct
        assert!(result.is_err());
        assert!(
            result.is_err_and(|x| x.kind() == io::ErrorKind::NotFound),
            "error kind is not found"
        );
    }

    #[test]
    /// NOTE: ok(), err()把Result<T, E>转换成Option<T>
    fn test_ok_or_err() {
        let result: Result<i32, Box<dyn error::Error>> = Ok(1);
        assert_eq!(result.ok(), Some(1));
        let result: Result<i32, Box<dyn error::Error>> = Err("error".into());
        assert_eq!(result.ok(), None);

        let result: Result<i32, &str> = Ok(10);
        assert_eq!(result.err(), None);
        let result: Result<i32, &str> = Err("error");
        assert_eq!(result.err(), Some("error"));
    }

    #[test]
    fn test_as_ref() {
        let result: Result<i32, &str> = Ok(2);
        assert_eq!(result.as_ref().unwrap(), &2);
    }

    #[test]
    /// NOTE: as_mut(): Converts from &mut Result<T, E> to Result<&mut T, &mut E>.
    fn test_as_mut() {
        let mut result: Result<i32, &str> = Ok(2);
        mutate(&mut result);
        assert_eq!(result.unwrap(), 42);

        {
            let mut result: Result<i32, &str> = Ok(2);
            assert_eq!(result.as_mut(), Ok(&mut 2));
        }

        fn mutate(r: &mut Result<i32, &str>) {
            match r.as_mut() {
                Ok(v) => *v = 42,
                Err(e) => *e = "error",
            }
        }
    }

    #[test]
    #[allow(unused_variables)]
    /// NOTE: map(), map_or(), map_or_else()
    /// default: error, F: FnOnce(E) -> F
    fn test_map() {
        let k = 13;

        let result: Result<i32, &str> = Ok(2);
        assert_eq!(result.map(|x| x * 2), Ok(4));
        assert_eq!(result.map_or(42, |x| x * 3), 6);
        assert_eq!(result.map_or_else(|e| k * 2, |x| x * 4i32), 8i32);

        let result: Result<i32, &str> = Err("error");
        assert_eq!(result.map(|x| x * 2), Err("error"));
        assert_eq!(result.map_or(42, |x| x * 2), 42);
        assert_eq!(result.map_or_else(|e| k * 3, |x| x * 2), 39);
    }

    #[test]
    fn test_question_mark() -> Result<(), Box<dyn error::Error>> {
        let mut stack = vec![1, 2, 3, 4];
        // 测试 error
        // let mut stack = vec![1];
        let result = add_last_two_numbers(&mut stack)?;
        println!("result: {:?}", result);
        return Ok(());
        fn add_last_two_numbers(stack: &mut Vec<i32>) -> Result<i32, Box<dyn error::Error>> {
            Ok(stack.pop().ok_or("Stack too small")? + stack.pop().ok_or("Stack too small")?)
        }
    }
}
